<?php


namespace App\Http\Controllers\Admin;


use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;

class RedisTextController extends Controller
{
    private $redis;
    public function __construct(Redis $redis)
    {
        $this->redis = $redis;
    }

    public function text()
    {
        $key1 = 'hash:user:hash1';
        $key2 = 'hash:user:hash2';
        $key3 = 'hash:user:hash3';

        $array = [
            'id' => '1',
            'name' => 'xin小四',
            'sex' => '1'
            ];
//        dd(json_encode($array));
//        Redis::set($key2, json_encode($array));

        $data = Redis::hGetAll($key1);
        return $data;
    }

    public function string()
    {

        $key = 'string:key';
        $value = 'string:value';
//        $a = Redis::flushDb();
        //设置key-value
        Redis::set('string:001', 'string001');
        Redis::set('string:002', 'string002');
        Redis::set('string:003', 'string003');

//        $mget = Redis::mget(array('number','key')); // 批量获取键值,返回一个数组
//        Redis::mset(array('key0' => 'value0', 'key1' => 'value1')); // 批量设置键值
//        Redis::msetnx(array('key0' => 'value0', 'key1' => 'value1'));// 批量设置键值，类似将setnx()方法批量操作
//        dump('string:003值为:'.Redis::get('string:003'));
//        dump(Redis::mget(['string:001', 'string:002', 'string:003']));

        //设置有效期为5秒的键值
        Redis::setex('string:setex', 600, 'setex');
        //设置有效期为5000毫秒(同5秒)的键值
        Redis::psetex('string:psetex', 5000, 'psetex');
        //若键值存在返回false 不存在返回true
        Redis::setnx('string:setnx', 'setnx');
        //删除键值 可以传入数组 array('key1','key2')删除多个键
        Redis::delete('string:key');
        //将键key的值设置为XK， 并返回这个键值原来的值TK
        Redis::getSet('string:key', 'XK');
        //验证键是否存在，存在返回true
        Redis::exists('string:key');

//        Redis::set('string:number', 1);
//        Redis::incr('string:number'); //键值加1
//        Redis::incrby('string:number', -10); //键值加减10
//        Redis::incrByFloat('string:number', -1.5); //键值加减小数
//        Redis::decr('string:number'); // 键值减1
//        Redis::decrBy('string:number', 10); // 键值减10

        Redis::append('string:key', '-Smudge'); //原键值TK，将值追加到键值后面，键值为TK-Smudge
//        Redis::getRange('key', 0, 5); // 键值截取从0位置开始到5位置结束
//        Redis::getRange('key', -6, -1); // 字符串截取从-6(倒数第6位置)开始到-1(倒数第1位置)结束
//        Redis::setRange('key', 0, 'Smudge');// 键值中替换字符串，0表示从0位置开始//有多少个字符替换多少位置，其中汉字占2个位置

        dump(Redis::strlen('string:key')); //键值长度
        dd('this is end');

        //批量事务处理,不保证处理数据的原子性
        $ret = Redis::multi()
            ->set('string:001', 'set')
            ->get('string:001')
            ->setnx('string:001', 'setnx')
            ->get('string:001')
            ->exec();
        dump($ret);
//        Redis::watch('key');   // 监控键key 是否被其他客户端修改//如果KEY在调用watch()和exec()之间被修改，exec失败
    }

    public function message()
    {

        $channel_name = 'channel';
        $msg = 'loading';
        Redis::publish($channel_name, 'hello world!!!'); // send message.
        dd(1);
        Redis::subscribe(array($channel_name), function ($channel_name, $msg) {
            echo "channel:".$channel_name.",message:".$msg."\n";
        }); // subscribe to 3
        $this->message();
        return [];
    }

    public function list()
    {
        $left = 'list:left:left';
        $right = 'list:right:right';

//        for ($i = 0 ;$i < 5; $i++) {
//            Redis::lPush($left, $i+1); //插入链表头部/左侧，返回链表长度
//            Redis::rPush($right, $i+1); //插入链表尾部/右侧，返回链表长度
//        }
//
//        Redis::lPushx($left, 'A');// 插入链表头部/左侧,链表不存在返回0，存在即插入成功，返回当前链表长度
//        Redis::rPushx($left, 'B');// 插入链表尾部/右侧,链表不存在返回0，存在即插入成功，返回当前链表长度
//        Redis::delete('list-key'); // 删除链表
//        Redis::lSet($left, 0, 'X'); //0位置元素替换为 X

        dump(Redis::lRange($left, 0, -1));
        dump(Redis::lRange($right, 0, -1));

//        dump(Redis::lPop($left));//返回LIST顶部（左侧）的VALUE ,后入先出(栈)
//        dump(Redis::rPop($left));//返回LIST尾部（右侧）的VALUE ,先入先出（队列）
        dump(Redis::lSize($left));// 如果是链表则返回链表长度，空链表返回0
        dump( Redis::lGet($left, 0)); //若不是链表或者不为空，则返回false ,判断非链表 " === false "// 通过索引获取链表元素 0获取左侧一个  -1获取最后一个
        dump(Redis::lRange($left, 0, 3));//链表截取 从0开始 3位置结束 ，结束位置为-1 获取开始位置之后的全部
//        dump(Redis::lTrim($left, 0, 1));// 截取链表(不可逆) 从0索引开始 1索引结束
//        dump();


        exit();


        Redis::lRem($left, 'C', 2); //链表从左开始删除元素2个C
        Redis::lInsert($left, Redis::BEFORE, 'C', 'X');// 在C元素前面插入X  , Redis::AfTER(表示后面插入)
        //链表不存在则插入失败 返回0 若元素不存在返回-1
        Redis::rpoplpush($left, 'list-key2');//从源LIST的最后弹出一个元素
        //并且把这个元素从目标LIST的顶部（左侧）压入目标LIST。
        Redis::brpoplpush();                    //rpoplpush的阻塞版本，这个版本有第三个参数用于设置阻塞时间
        //即如果源LIST为空，那么可以阻塞监听timeout的时间，如果有元素了则执行操作。
    }

    public function set()
    {
        $set = 'set:set:001';
        $set2 = 'set:set:002';
        $set3 = 'set:set:003';
        for ($i = 0; $i < 10; $i++) {
            Redis::sAdd($set, $i);// (从左侧插入,最后插入的元素在0位置),集合中已经存在元素 则返回false,不存在添加成功 返回true
            Redis::sAdd($set2, $i-2);
            Redis::sAdd($set3, $i+2);
        }

        Redis::sAdd($set, 'TK');
        Redis::sAdd($set, 'AAA');
        Redis::sAdd($set, 'BBB');
        Redis::sRem($set , 'CCC'); // 移除容器中的TK
        Redis::sMove($set, $set2, 'TK'); //将容易$set中的元素TK 移动到容器$set1  操作成功返回TRUE

        $members = Redis::sMembers($set); //获取容器$set中所有元素
        $count = Redis::sCard($set); //返回SET容器的成员数
        $exists = Redis::sIsMember($set,'TK'); //检查VALUE是否是SET容器中的成员
        $pop = Redis::sPop($set2); //随机返回容器中一个元素，并移除该元素
        $rand = Redis::sRandMember($set2);//随机返回容器中一个元素，不移除该元素
        $inter = Redis::sInter($set, $set2);// 返回两个集合的交集 没有交集返回一个空数组，若参数只有一个集合，则返回集合对应的完整的数组
        Redis::sInterStore('set:set:inter_store', $set, $set2); //将集合$set和集合$set1的交集 存入容器store 成功返回1

        $union = Redis::sUnion($set, $set2);//集合$set和集合$set1的并集  注意即使多个集合有相同元素 只保留一个
        Redis::sUnionStore('set:set:union_store', $set, $set2);

        $diff = Redis::sDiff($set, $set3, $set2); //返回数组，该数组元素是存在于$set集合而不存在于集合$set1 $set2

        dump($members);
        dump('成员数:'.$count);
        dump($exists);
        dump($pop);
        dump('随机获取:'.$rand);
        dump($inter);
        dump($union);
        dump($diff);



        exit();





    }

    public function zset()
    {
        /**
         * (stored set) 和 set 一样是字符串的集合，
         * 不同的是每个元素都会关联一个 double 类型的 scoreredis的list类型其实就是一个每个子元素都是string类型的双向链表。
         **/

        $key = 'zset:zset:key';
        $key1 = 'zset:zset:key1';
        $key2 = 'zset:zset:key2';

        for ($i = 0; $i < 10; $i++) {
            $value = chr(ord('A') + $i);
            //插入集合$key中，A元素关联一个分数，插入成功返回1;同时集合元素不可以重复, 如果元素已经存在返回 0
            Redis::zAdd($key, rand(0, 10), $value);
        }
        Redis::zDelete($key, 'B'); // 移除集合key中元素B  成功返回1 失败返回 0

        $range = Redis::zRange($key,0,-1); // 获取集合元素，从0位置 到 -1 位置
        $range_score = Redis::zRange($key,0,-1, true);// 获取集合元素，从0位置 到 -1 位置, 返回一个关联数组 带分数
        $rev_range = Redis::zRevRange($key, 0, -1); // 获取集合元素，从0位置 到 -1 位置，数组按照score降序处理
        $rev_range_sort =Redis::zRevRange($key, 0, -1, true);// 获取集合元素，从0位置 到 -1 位置，数组按照score降序处理 返回score关联数组
        dump($range);
        dump($range_score);
        dump($rev_range);
        dump($rev_range_sort);

        $score = Redis::zScore($key, 'A'); // 返回集合key中元素A的score值
        $rank = Redis::zRank($key, 'A');// 返回集合key中元素A的索引值
        $count = Redis::zCount($key, 2, 10); // 获取key中score在区间[2, 10]元素的个数
        dump("A的score: ".$score);
        dump("A的索引: ".$rank);
        dump("统计区间中的个数: ".$count);

        //获取几个key中score在区间[0,5]元素 ,score由低到高排序,
        //元素具有相同的score，那么会按照字典顺序排列 , withscores 控制返回关联数组
        $by_score = Redis::zRangeByScore($key, 0, 5, ['withscores' => true]);
        //其中limit中 0和1 表示取符合条件集合中 从0位置开始，向后扫描1个 返回关联数组
        $by_limit = Redis::zRangeByScore($key, 0, 5, array('withscores' => TRUE, "limit" => array(1, 1)));
        dump($by_score);
        dump($by_limit);

        //返回存储在key对应的有序集合中的元素的个数
        $size = Redis::zSize($key);
        $card = Redis::zCard($key);
        dump("size()元素的个数 ".$size);
        dump("card()元素的个数 ".$card);

        Redis::zRemRangeByScore($key, 1, 3); // 移除key中score在区间[1, 3](含边界)的元素
        Redis::zRemRangeByRank($key, 0, 1);//默认元素score是递增的，移除key中元素 从0开始到1位置结束

        Redis::zIncrBy($key, 2.5, 'A'); // 将集合key中元素A的score值 加 2.5

        // 将集合key和集合key1元素合并于集合union , 并且新集合中元素不能重复返回新集合的元素个数，
        // 如果元素A在key和key1都存在，则合并后的元素A的score相加
        Redis::zUnion('union', array($key, 'key1'));
        // 集合k1和集合k2并集于k02 ，array(5,1)中元素的个数与子集合对应，然后 5 对应k1
        //k1每个元素score都要乘以5 ，同理1对应k2，k2每个元素score乘以1
        //然后元素按照递增排序，默认相同的元素score(SUM)相加
        Redis::zUnion('ko2', array('k1', 'k2'), array(5, 2));
        // 各个子集乘以因子之后，元素按照递增排序，相同的元素的score取最大值(MAX)也可以设置MIN 取最小值
        Redis::zUnion('ko2', array('k1', 'k2'), array(10, 2),'MAX');


        // 集合k1和集合k2取交集于k01 ，且按照score值递增排序
        //如果集合元素相同，则新集合中的元素的score值相加
        Redis::zInter('ko1', array('k1', 'k2'));
        //集合k1和集合k2取交集于k01 ，array(5,1)中元素的个数与子集合对应，然后 5 对应k1
        //k1每个元素score都要乘以5 ，同理1对应k2，k2每个元素score乘以1
        //，然后元素score按照递增排序，默认相同的元素score('SUM');//相加
        Redis::zInter('ko1', array('k1', 'k2'), array(5, 1));
        // 各个子集乘以因子之后，元素score按照递增排序，相同的元素score取最大值(MAX)
        //也可以设置MIN 取最小值
        Redis::zInter('ko1', array('k1', 'k2'), array(5, 1),'MAX');

        exit();

    }

    public function hash()
    {
        //redis hash是一个string类型的field和value的映射表.它的添加，删除操作都是O(1)（平均）.hash特别适合用于存储对象。
        $array = [
            'id' => '1',
            'name' => 'xinxiaosi',
            'sex' => '1',
            'age' => '24',
            'account' => '1252597511@qq.com',
        ];
        $key = 'hash:hash:';
        $key1 = 'hash:hash:001';
        $key2 = 'hash:hash:user';

        Redis::hSet($key1, 'name', 'TK'); // 在h表中 添加name字段 value为TK
        Redis::hSetNx($key1, 'name', 'TK'); // 在h表中 添加name字段 value为TK 如果字段name的value存在返回false 否则返回 true
        Redis::hMset($key2, $array); // 表h 批量设置字段和value

        // 获取h表中所有字段
        $key2_key = Redis::hKeys($key2);
        dump($key2_key);

        // 获取h表中所有字段value
        $val = Redis::hVals($key2);
        dump($val);

        // 获取h表中name字段value
        $get = Redis::hGet($key2, 'name');
        dump('name = '.$get);

        // 表h 批量获取字段的value
        $mget = Redis::hMGet($key2, $key2_key);
        dump($mget);

        // 获取h表长度即字段的个数
        $length = Redis::hLen($key2);
        dump($length);

        // 获取h表中所有字段和value 返回一个关联数组(字段为键值)
        $all = Redis::hGetAll($key2);
        dump($all);

        exit();
        return [];


        Redis::hDel('h','email'); // 删除h表中email 字段
        Redis::hExists('h', 'email'); //判断email 字段是否存在与表h 不存在返回false

        Redis::hSet('h', 'age', 28);
        Redis::hIncrBy('h', 'age', -2);
        // 设置h表中age字段value加(-2) 如果value是个非数值 则返回false 否则，返回操作后的value
        Redis::hIncrByFloat('h', 'age', -0.33);
        // 设置h表中age字段value加(-2.6) 如果value是个非数值 则返回false 否则
        // 返回操作后的value(小数点保留15位)

    }
}
